<?PHP
	/*
		Zip extraction function by Alexandre Tedeschi, alexandrebr at gmail dot com
		
		Modified extensively by psoTFX and DavidMJ, (c) phpBB Group, 2003
		
		Based on work by Eric Mueller and Denis125
		Official ZIP file format: http://www.pkware.com/appnote.txt
	
		Further modified by Tim Chamness for use with X7 Chat, (c) X7 Group 2007
	*/

	class lib_zip {

		function extract($file,$dest,$flatten=false,$filter=''){
			if(!is_writable($dest))
				return 'writepermdenied';

			$file = fopen($file,'rb');
	
			$dd_try = false;
	
			while(!feof($file)){
				// Check if the signature is valid...
				$signature = fread($file, 4);
	
				switch ($signature){
					// This is the start of a file
					case "\x50\x4b\x03\x04":
						// Load information from the file
						// We don't store the version needed to extract, the general purpose bit flag or the date and time fields
						$data = unpack("@4/vc_method/@10/Vcrc/Vc_size/Vuc_size/vname_len/vextra_field",fread($file, 26));
						$file_name = fread($file,$data['name_len']);
	
						if($data['extra_field'])
							fread($file,$data['extra_field']);
	
						if($flatten){

							if(!$data['uc_size'] && !$data['crc'] && substr($file_name, -1, 1) == '/')
								continue;
	
							$tfileinfo = pathinfo($file_name);
							$unique_file_id = -1;
							$tfileinfo['filename'] = preg_replace("#\\.".preg_quote($tfileinfo['extension'],"#")."$#",'',$tfileinfo['basename']);
							do {
								$unique_file_id++;
								$target_filename = $dest.'/'.$tfileinfo['filename'].(($unique_file_id == 0) ? '' : '_'.$unique_file_id).'.'.$tfileinfo['extension'];
							} while(file_exists("$target_filename"));
							
						}else{
						
							$target_filename = "$dest/$file_name";

							if(!$data['uc_size'] && !$data['crc'] && substr($file_name, -1, 1) == '/'){
								if(!is_dir($target_filename)){
									$str = '';
									$folders = explode('/', $target_filename);
		
									// Create and folders and subfolders if they do not exist
									foreach($folders as $folder){
										$str = (!empty($str)) ? $str . '/' . $folder : $folder;
										if(!is_dir($str)){
											mkdir($str,0777);
											chmod($str,0777);
										}
									}
								}
								// This is a directory, we are not writting files
								continue;
							}else{
								// Some archivers are punks, they don't don't include folders in their archives!
								$str = '';
								$folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME));
		
								// Create and folders and subfolders if they do not exist
								foreach ($folders as $folder){
									$str = (!empty($str)) ? $str . '/' . $folder : $folder;
									if (!is_dir($str)){
										mkdir($str,0777);
										chmod($str,0777);
									}
								}
							}

						}
	
						$content = !$data['uc_size'] ? '' : fread($file,$data['c_size']);
						
						if(empty($filter) || preg_match($filter,$file_name)){
	
							$fp = fopen($target_filename,"w");
		
							switch($data['c_method']){
								case 0:
									// Not compressed
									fwrite($fp,$content);
								break;
								case 8:
									// Deflate
									fwrite($fp,gzinflate($content,$data['uc_size']));
								break;
								case 12:
									// Bzip2
									fwrite($fp,bzdecompress($content));
								break;
							}
							
							fclose($fp);
							
						}
					break;
					case "\x50\x4b\x01\x02":
					case "\x50\x4b\x05\x06":
						// Finished extracting
					break 2;
					case 'PK00':
						// Ignore and continue
					continue 2;
					// We have encountered a header that is weird. Lets look for better data...
					default:
						if(!$dd_try){
							// Unexpected header. Trying to detect wrong placed 'Data Descriptor';
							$dd_try = true;
							fseek($file,8,SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4)
							continue 2;
						}
						return 'corruptzip';
					break 2;
				}
	
				$dd_try = false;
			}

			return true;
		}

	}
?>